home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / tcoop.arc / TCOOP2.ARC / ISOUNIT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-26  |  21.6 KB  |  755 lines

  1. // isounit.cpp: Iso Class Implementation
  2.  
  3. #include "keybrd.h"
  4. #include "isounit.h"
  5. #include "msmouse.h"
  6.  
  7. MsgPkt NullMsg = { NULL, Idle, Idle, 0, 0, "" };
  8.  
  9. Iso::Iso(Fso *P)
  10. // Initializes the Iso by setting all of the instance variables to
  11. // a default state and sets up an IsoMgr object 
  12. {
  13.   Panel = P;                 // P is either a Tfso or Gfso
  14.   Active = False;            // Not selected
  15.   Visible  = False;          // Object is not visible
  16.   IsClosed = True;           // Object is not open
  17.   TouchFlag = False;         // Object is not touching another Iso
  18.   ClipToFrame = False;       // Normally, clip to the interior
  19.   Under = NULL; Over = NULL; // The Iso stack is empty
  20.   Base = NULL;               // No base to start with
  21.   SubMgr = new IsoMgr(this); // Make an IsoMgr for this object
  22. }
  23.  
  24. Iso::~Iso(void)
  25. // De-allocates memory for an Iso by first removing the object
  26. // from its Base's Iso stack and it destroys its own stack 
  27. {
  28.   Remove(); // Hide() & remove from Iso stack
  29.   delete SubMgr;
  30.   delete Panel; 
  31. }
  32.  
  33. Rso *Iso::ClippingRect(void)
  34. // Given the state of the ClipToFrame flag, returns the
  35. // appropriate clipping rectangle
  36. {
  37.   if (ClipToFrame) 
  38.      return Base->Panel->Frame;
  39.      else return Base->Panel->Interior;
  40. }
  41.  
  42. void Iso::SetLocn(int Xl, int Yl, CoordType Ctype)
  43. // Sets the location of the Iso. If Ctype == Relc, the
  44. // coordinates are relative to the object's base. If the
  45. // object does not have a base, (like for FullScrn), then
  46. // it's assumed the coordinates are always absolute, and
  47. // that SetLocn is only called once.
  48. {
  49.   int Dx, Dy, Dw, Dh;
  50.   Iso *P;
  51.   Rso *Clipper;
  52.  
  53.   if (Base == NULL) {        // Object does not have a base 
  54.      Panel->SetLocn(Xl, Yl); // (Like FullScrn)
  55.   }
  56.   else { // Object has a base
  57.      Clipper = ClippingRect();
  58.      if (Ctype == Relc) {   // Use relative coords
  59.         Xl += Clipper->Xul; // Turn into absolute coords
  60.         Yl += Clipper->Yul; // Turn into absolute coords
  61.      }
  62.      // Make sure coordinates are in range. It's assumed that
  63.      // the size is OK at this point.
  64.      Dw = Panel->Frame->Wd; Dh = Panel->Frame->Ht;
  65.      Clipper->ClipDim(Xl, Yl, Dw, Dh); 
  66.      // Record distance to move for all dependent objects
  67.      Dx = Xl - Panel->Frame->Xul;
  68.      Dy = Yl - Panel->Frame->Yul;
  69.      // Change location of the object
  70.      Panel->SetLocn(Xl, Yl);
  71.      // Change locations of all dependent objects
  72.      P = SubMgr->Top;
  73.      while (P != NULL) {
  74.        P->SetLocn(P->Panel->Frame->Xul+Dx, P->Panel->Frame->Yul+Dy, Absc);
  75.        P = P->Under;  // Get next object on stack
  76.      }
  77.   }
  78. }
  79.  
  80. void Iso::SetSize(int W, int H)
  81. // The size of an Iso is the size of it's panel. W and H are
  82. // the new size of the interior. First, we set the size of
  83. // the panel, which will set the sizes of the interior, frame,
  84. // and overall rectangles. Then, if we have a base, we clip the
  85. // frame size to it. If the frame size changes during clipping,
  86. // we re-size the panel w.r.t interior again.
  87. {
  88.   int Dw, Dh, Ow, Oh;
  89.   Rso *Clipper;
  90.   Rso *Pf = Panel->Frame;
  91.  
  92.   Panel->SetSize(W, H); // First set up panel size
  93.   if (Base != NULL) {   // Do we have a base to clip to?
  94.      Clipper = ClippingRect();
  95.      Pf = Panel->Frame;
  96.      Ow = Pf->Wd; Oh = Pf->Ht;           // Record old frame size
  97.      Clipper->ClipSize(Pf->Wd, Pf->Ht);  // Adjust frame size
  98.      Dw = Pf->Wd - Ow; Dh = Pf->Ht - Oh; // Compute delta size
  99.      if ((Dw != 0) || (Dh != 0)) { 
  100.         // Need to set the size of the panel again
  101.         Panel->SetSize(Panel->Interior->Wd+Dw, Panel->Interior->Ht+Dh);
  102.      }   
  103.   }
  104. }
  105.  
  106. void Iso::DrawPanel(void)
  107. // First, initializes the swap buffer by calling GetImage,
  108. // draws the frame, draws the shadows, clears the
  109. // interior, and calls the specialized draw routine.
  110. {
  111.   Mouse.Hide();
  112.   Visible = True;  // We'll be visible soon
  113.   if (Panel->IsSwappable()) Panel->GetImage(ClippingRect()); 
  114.   Panel->DrawFrame(0, 0); 
  115.   Panel->DrawShadows(ClippingRect(), GetIm, 1);
  116.   Panel->Clear(' ', 0);   
  117.   Draw();
  118.   Mouse.Show();
  119. }
  120.  
  121. void Iso::Open(Iso *B, int X, int Y)
  122. // Opens the object by drawing it on a specified base at
  123. // position X,Y relative to the base. Since we now have a
  124. // base, we also clip the size w.r.t to the base. (It's assumed
  125. // that SetSize has already been called at least once.) 
  126. {
  127.   Base = B;
  128.   // Push the object onto its base managers' stack
  129.   Base->SubMgr->Push(this);
  130.   IsClosed = False;    // Object now to be open
  131.   // Adjust size if necessary. Can do this by calling SetSize, 
  132.   // which will in turn call ClipSize.
  133.   SetSize(Panel->Interior->Wd, Panel->Interior->Ht); 
  134.   SetLocn(X, Y, Relc); // Use relative coordinates
  135.   DrawPanel();         // Draw an empty panel
  136. }
  137.  
  138. void Iso::Reopen(int X, int Y)
  139. // Re-opens an object that was previously closed. The new
  140. // location (X,Y) is relative to the base
  141. {
  142.   IsClosed = False;
  143.   SetLocn(X, Y, Relc);
  144.   Select(); // Move Iso to front and show
  145. }
  146.  
  147. void Iso::Move(int X, int Y)
  148. // Moves the object to new location. Absolute coordinates
  149. // are used.
  150. {
  151.   if (Panel->IsSwappable()) { // Only swappable objects
  152.      Hide();                  // can be moved
  153.      SetLocn(X, Y, Absc);
  154.      Show();
  155.   }
  156. }
  157.  
  158. void Iso::DeltaMove(int Dx, int Dy)
  159. // Moves the object by an incremental amount
  160. {
  161.   // Add in the object's origin 
  162.   Move(Panel->Frame->Xul+Dx, Panel->Frame->Yul+Dy);  
  163. }
  164.  
  165. void Iso::MoveLoop(MsgPkt &M)
  166. // Moves an object until mouse button is released
  167. {
  168.   unsigned E;
  169.   Mouse.Moved(); // Resets counters
  170.   do {
  171.     if (Mouse.Moved()) DeltaMove(Mouse.Dx, Mouse.Dy);
  172.     E = Mouse.Event(M.Mx, M.My);
  173.   } while (E != MouseUp);
  174.   M.RtnCode = Idle;
  175. }
  176.  
  177. void Iso::Stretch(int W, int H)
  178. // Stretch to a new size. First, closes all sub-windows and figure
  179. // out the minimum size we can stretch to, hides this object, does 
  180. // the resize, and redraws everybody.
  181. {
  182.   Iso *P;
  183.   int Mw, Mh;
  184.  
  185.   if (Panel->IsStretchable()) {
  186.      // Hide the subiso's. While we're at it, find maximum
  187.      // size of subiso's, which serves as our minimum.
  188.      Mw = 8; Mh = 3;  // Absolute minimums
  189.      P = SubMgr->Top; 
  190.      while (P != NULL) { // Hide all sub-windows
  191.        if (P->Panel->Frame->Wd > Mw) Mw = P->Panel->Frame->Wd;
  192.        if (P->Panel->Frame->Ht > Mh) Mh = P->Panel->Frame->Ht;
  193.        P->Hide();
  194.        P = P->Under;
  195.      } 
  196.      if (W < Mw) W = Mw; // Adjust sizes to lower bound
  197.      if (H < Mh) H = Mh;
  198.      Hide(); // Hide image
  199.      SetSize(W, H);
  200.      // This next call is to relocate the shadows
  201.      SetLocn(Panel->Frame->Xul, Panel->Frame->Yul, Absc); 
  202.      Redraw();
  203.      P = SubMgr->Bottom; 
  204.      while (P != NULL) { // Reshow the sub-windows 
  205.         P->SetLocn(P->Panel->Frame->Xul, P->Panel->Frame->Yul, Absc);
  206.         if (!P->IsClosed) P->Show();
  207.         P = P->Over;
  208.      } 
  209.   }
  210. }
  211.  
  212. void Iso::DeltaStretch(int Dw, int Dh)
  213. // Do an incremental stretch 
  214. {
  215.   Stretch(Panel->Interior->Wd+Dw, Panel->Interior->Ht+Dh);
  216. }
  217.  
  218. void Iso::StretchLoop(MsgPkt &M)
  219. // Stretches the window until a MouseUp event 
  220. {
  221.    unsigned E;
  222.    Mouse.Moved(); // Resets counters 
  223.    do {
  224.      if (Mouse.Moved()) DeltaStretch(Mouse.Dx, Mouse.Dy);
  225.      E = Mouse.Event(M.Mx, M.My);
  226.    } while (E != MouseUp);
  227.    M.RtnCode = Idle;
  228. }
  229.  
  230. void Iso::Swap(void)
  231. // Swap between the object's save buffer and the screen. The
  232. // shadow clipping region is set to the base's interior, unless
  233. // the Iso has no base, it's set to the Iso's overall rect. 
  234. {
  235.   XfrDirn Xd;
  236.   if (Visible) Xd = PutIm; else Xd = GetIm;
  237.   if (Base != NULL)
  238.      Panel->Swap(Base->Panel->Interior, Xd);
  239.      else Panel->Swap(Panel->Overall, Xd);
  240. }
  241.  
  242. void Iso::Hide(void)
  243. // Hides the object by swapping images 
  244. {
  245.   if (IsClosed) return;     // Don't hide if already closed    
  246.   if (Visible) {            // or already hidden               
  247.      Swap();                // Swap out the object             
  248.      SetVisibleFlag(False); // Recursively reset visible flags 
  249.   }
  250. }
  251.  
  252. void Iso::Show(void)
  253. // Shows the object by swapping images 
  254. {
  255.   if (IsClosed) return;     // Don't show if closed 
  256.   if (!Visible) {           // or already visible   
  257.      Swap();
  258.      SetVisibleFlag(True);  // Recursively set visible flags 
  259.   }
  260. }
  261.  
  262. void Iso::SetVisibleFlag(int F)
  263. // Recursively set/reset the visible flags of this 
  264. // object and all of its children 
  265. {
  266.   Iso *P;
  267.   if (IsClosed) return;
  268.   P = SubMgr->Top;  // Start at the top of the stack 
  269.   while (P != NULL) {
  270.     P->SetVisibleFlag(F);
  271.     P = P->Under;
  272.   }
  273.   Visible = F;
  274. }
  275.  
  276. void Iso::Select(void)
  277. // Selects an object to be the active screen object. When 
  278. // the object is selected it is brought to the front. 
  279. {
  280.   if (Base != NULL) {
  281.      Base->Select();  // Make sure parent is selected first 
  282.      // Then, select yourself 
  283.      Base->SubMgr->MoveToFront(this, True);
  284.   }
  285.   Show(); // Make sure it's showing 
  286. }
  287.  
  288. void Iso::Remove(void)
  289. // Removes the Iso by moving it to the front of the stack, and
  290. // detaching it from the stack. Set base to NULL to indicate
  291. // it no longer belongs to a stack. 
  292. {
  293.   if (Base != NULL) Base->SubMgr->MoveToFront(this, False);
  294.   Base = NULL;
  295. }
  296.  
  297. void Iso::Prompt(void)
  298. // Default prompt action is to select the object, and
  299. // set the Active flag 
  300. {
  301.   Select(); Active = True;
  302. }
  303.  
  304. void Iso::UnPrompt(void)
  305. // Default unprompt action is to merely set the Active
  306. // flag to false 
  307. {
  308.   Active = False;
  309. }
  310.  
  311. void Iso::SwitchFocus(MsgPkt &M)
  312. // Switch the focus to Self by first leaving the old focus
  313. // (if there was one), and entering Self. Don't need to
  314. // do anything if this object is already the focus 
  315. {
  316.   if (M.Focus != this) {     // Nothing to do  
  317.      if (M.Focus != NULL) {
  318.     M.Focus->Leave(M);   // Leave old focus 
  319.      }
  320.      M.Focus = this;         // Enter this object
  321.      Enter(M);
  322.   }
  323.   M.RtnCode = Idle;
  324. }
  325.  
  326. void Iso::Enter(MsgPkt &)
  327. // Default Enter action is to prompt the object if
  328. // not already active 
  329. {
  330.   if (!Active) Prompt();
  331. }
  332.  
  333. void Iso::Leave(MsgPkt &M)
  334. // Unprompts the object if it is active. If you are the
  335. // current focus, you MUST set the focus to nil 
  336. {
  337.   if (Active) UnPrompt();
  338.   if (M.Focus == this) M.Focus = NULL;
  339. }
  340.  
  341. // --------------------- Mouse event methods ---------------- 
  342.  
  343. void Iso::OnMouseEnter(MsgPkt &M)
  344. // If mouse button is down when the mouse enters this 
  345. // object, switch focus to this object
  346. {
  347.   if (Mouse.ButtonStatus() != 0) SwitchFocus(M);
  348. }
  349.  
  350. void Iso::OnMouseLeave(MsgPkt &M)
  351. // If mouse button is down when the mouse leaves this
  352. // object, then leave this object
  353. {
  354.   if (Mouse.ButtonStatus() != 0) Leave(M);
  355. }
  356.  
  357. void Iso::OnClose(MsgPkt &M)
  358. // On a Close event, hide this object and set it's closed flag 
  359. {
  360.   Leave(M);
  361.   // If if statement below traps the fullscrn case too 
  362.   if (Panel->IsCloseable()) {
  363.      Hide();
  364.      IsClosed = True;
  365.   }
  366. }
  367.  
  368.  
  369. void Iso::OnMouseDown(MsgPkt &M)
  370. // If mouse button pressed while inside this object, 
  371. // then switch focus to it, handle possibility of 
  372. // being on the border 
  373. {
  374.   SwitchFocus(M);
  375.   if (Panel->OnBorder(M.Mx, M.My)) BorderHandler(M);
  376. }
  377.  
  378. void Iso::BorderHandler(MsgPkt &M)
  379. // Handle border conditions: either activate close button,
  380. // stretch, or move the object. Stretching occurs if on
  381. // lower right-hand corner, UNLESS the window is only
  382. // 1x1 in size (eg. scroll buttons.) 
  383. {
  384.   if (Panel->OnCloseButton(M.Mx, M.My)) {
  385.      M.RtnCode = Close;
  386.      M.Focus= this;
  387.   }
  388.   else if ((M.Mx == Panel->Frame->Xlr) && 
  389.            (M.My == Panel->Frame->Ylr) &&
  390.            // These tests are so we don't cause Move() to
  391.            // to fail on Iso's like scroll buttons
  392.            (Panel->Frame->Wd > 1) && 
  393.            (Panel->Frame->Ht > 1))
  394.           {
  395.        StretchLoop(M);
  396.   }
  397.   else {
  398.     MoveLoop(M);
  399.   }
  400. }
  401.  
  402. // --------- Methods to process keyboard events -------- 
  403.  
  404. void Iso::OnKeyStroke(MsgPkt &M)
  405. // Process all key press events. Default is to handle only
  406. // the return key, and the shift arrow keys 
  407. {
  408.   switch (M.Code) {
  409.     case CrKey: 
  410.       Activate(M);
  411.       M.Code = Idle;
  412.     break;
  413.     default :
  414.     if (IsShiftArrow(M.Code)) {
  415.        OnShiftArrow(M);
  416.        M.Code = Idle;
  417.     }
  418.   }
  419. }
  420.  
  421. void Iso::OnShiftArrow(MsgPkt &M)
  422. // The shift arrow key events cause the window to move 
  423. {
  424.   switch (M.Code) {
  425.     case ShiftLeft  :  DeltaMove(-1, 0); break;
  426.     case ShiftRight :  DeltaMove(1, 0);  break;
  427.     case ShiftUpKey :  DeltaMove(0, -1); break;
  428.     case ShiftDnKey :  DeltaMove(0, 1);  break;
  429.     default: ;
  430.   }
  431. }
  432.  
  433. void Iso::Dispatch(MsgPkt &M)
  434. // Dispatches the events to the appropriate method 
  435. {
  436.    M.RtnCode = Idle;  // Default new message is to "idle" 
  437.    switch (M.Code) {
  438.      case Idle           :  break;
  439.      case StrMsg         :  break;
  440.      case Close          :  OnClose(M); break;
  441.      case MouseDown      :  OnMouseDown(M); break;
  442.      case MouseStillDown :  OnMouseStillDown(M); break;
  443.      case MouseUp        :  OnMouseUp(M); break;
  444.      case MouseEnter     :  OnMouseEnter(M); break;
  445.      case MouseLeave     :  OnMouseLeave(M); break;
  446.      case MouseWithin    :  OnMouseWithin(M); break;
  447.      default: ;
  448.        OnKeyStroke(M);
  449.    }
  450. }
  451.  
  452. int Iso::Obscured(void)
  453. // Returns true if Self is partially hidden by object from above 
  454. {
  455.   Iso *Ip = Over;
  456.   while (Ip != NULL) {
  457.     if (Panel->Touches(Ip->Panel)) {
  458.        return True;
  459.     }
  460.     Ip = Ip->Over;
  461.   }
  462.   return False;
  463. }
  464.  
  465. // ----------------------- IsoMgr Methods ----------------------- 
  466.  
  467. IsoMgr::IsoMgr(Iso *B)
  468. // Initializes the IsoMgr object by setting the top and bottom
  469. // stack pointers to NULL, and recording who's the base. 
  470. {
  471.   Top  = NULL;  Bottom = NULL;
  472.   Base = B;
  473.   Hot = NULL;
  474.   Marker = NULL;
  475. }
  476.  
  477. IsoMgr::~IsoMgr(void)
  478. // Destroys all Iso's on the stack 
  479. {
  480.   Iso *P, *Q;
  481.   P = Top;
  482.   while (P != NULL) {
  483.     Q = P->Under;
  484.     delete P;
  485.     P = Q;
  486.   }
  487. }
  488.  
  489. void IsoMgr::Push(Iso *Ip)
  490. // Attachs the Iso by pushing onto the Iso stack 
  491. {
  492.   if (Top != NULL) {
  493.      Top->Over = Ip;  // Link top of stack to new node 
  494.      Ip->Under = Top; // Link new node to top of stack 
  495.   }
  496.   else {              // First one on the stack        
  497.     Ip->Over  = NULL;
  498.     Ip->Under = NULL;
  499.     Bottom   = Ip;    // Make it the bottom too 
  500.     Marker   = Ip;    // Set the marker on it 
  501.   }                       
  502.   Top = Ip;           // Set top of stack to new node  
  503. }
  504.  
  505. void IsoMgr::MoveToFront(Iso *Me, int Keep)
  506. // If Keep == 1, MoveToFront moves Me to the top of the stack 
  507. // and makes it the active Iso.                                      
  508. // If Keep == 0, Me is removed from the stack and hidden. Note   
  509. // that nothing happens if Me is already at the top and we wish 
  510. // to keep it there. Also, if not keeping Me, it is simply detached  
  511. // from the stack, it is not destroyed!                              
  512. {
  513.   Iso *Ip;
  514.  
  515.   if (Keep && (Me == Top)) return; // Short circuit 
  516.   Mouse.Hide();
  517.   // If Me is an overlapping Iso, move its image to the top 
  518.   if (Me->Panel->IsSwappable()) {  // Must erase image at old posn 
  519.      ResetTouchFlags(Me);
  520.      SetTouchFlags(Me);
  521.      if (!Me->TouchFlag) {     // Nobody overlaps from above 
  522.         if (!Keep) Me->Hide(); // Erase image if deleting    
  523.      }
  524.      else { // Somebody overlaps from above, so ... 
  525.         // Swap iso's in descending order, downto me    
  526.         Ip = Top;
  527.         while (Ip != Me->Under) {
  528.           if (Ip->TouchFlag) Ip->Hide();
  529.           Ip = Ip->Under;
  530.         }
  531.         // Put Iso images (only those above me) back 
  532.         Ip = Me->Over;
  533.         while (Ip != NULL) {
  534.           if (Ip->TouchFlag) Ip->Show();
  535.           Ip = Ip->Over;
  536.         }
  537.      }
  538.   }
  539.     // Through processing overlapping windows so
  540.     // link up window underneath Me with the Iso above it 
  541.     // Note: if Me == Top, it is also true that we're
  542.     // deleting Me 
  543.  
  544.   if (Me == Top) {       // We know we're deleting 
  545.      if (Me == Bottom) { // Stack will be empty 
  546.         Bottom = NULL;
  547.         Top = NULL;
  548.      }
  549.      else {              // Iso underneath to become new top 
  550.         Me->Under->Over = NULL;
  551.         Top = Me->Under;
  552.      }
  553.      Me->Under = NULL;   // Reset under/over pointers        
  554.      Me->Over  = NULL;
  555.   }
  556.   else {
  557.     // Me is not top, and we may or may not be deleting           
  558.     // at this point, we know we have at least two Iso's on stack 
  559.     if (Me == Bottom) { // We're getting a new bottom       
  560.        Me->Over->Under = NULL;
  561.        Bottom = Me->Over;
  562.     }
  563.     else { // We're somewhere in the middle 
  564.        Me->Under->Over = Me->Over;
  565.        Me->Over->Under = Me->Under;
  566.     }
  567.     if (Keep) {  // Want to make me the new top iso 
  568.        Top->Over = Me;
  569.        Me->Under = Top;
  570.        Me->Over  = NULL;
  571.        Top = Me;
  572.        if (Me->TouchFlag) Me->Show(); // Put back image 
  573.     }
  574.     else { // Reset under/over pointers 
  575.        Me->Under = NULL; Me->Over = NULL;
  576.     }
  577.   }
  578.   Mouse.Show();
  579. }
  580.  
  581. Iso *CycleToSibling(Iso *Curr)
  582. // An auxiliary recursive function of CycleForw that find's
  583. // a sibling to cycle to. Note: This is not a method! 
  584. {
  585.   Iso *I;
  586.  
  587.   I = Curr->Base;  // Is there a base ?                  
  588.   if (I == NULL) { // No, so we don't belong to a stack  
  589.      I = Curr;     // so about all we can do is stay put 
  590.   }
  591.   else { // We belong to a stack 
  592.     I = Curr->Base->SubMgr->Bottom;   // Possibly our sibling 
  593.     // Scan for first visible sibling, but stop if you hit marker 
  594.     while ((I != NULL) && (!I->Visible) &&
  595.        (I != Curr->Base->SubMgr->Marker)) I = I->Over;
  596.     // If no sibling, or we've already been there ... 
  597.     if ((I == NULL) || (I == Curr->Base->SubMgr->Marker)) {
  598.        I = CycleToSibling(Curr->Base); // Try going forward from base 
  599.     } // Else we'll take i 
  600.   }
  601.   return I;
  602. }
  603.  
  604. Iso *IsoMgr::CycleForw(Iso *Curr)
  605. // Cycle forward through the stacks looking for someone
  606. // to become the new focus 
  607. {  
  608.   Iso *I;
  609.  
  610.   if (Curr == NULL) return NULL;
  611.   I = Curr->SubMgr->Bottom;     // I == first child  
  612.   // Scan for a visible child 
  613.   while ((I != NULL) && (!I->Visible)) I = I->Over;
  614.   // If no child, try to go to sibling 
  615.   if (I == NULL) I = CycleToSibling(Curr);
  616.   return I;
  617. }
  618.  
  619. void IsoMgr::ProcessCycle(MsgPkt &M)
  620. // A TabKey event means to cycle forward. A ShiftTabKey means
  621. // to cycle backwards (currently not implemented). 
  622. {
  623.   Iso *NewIso;
  624.   if ((M.Code == TabKey) || (M.Code == ShiftTabKey)) {
  625.      if (M.Focus == NULL) {
  626.     if ((Bottom != NULL) && Bottom->Visible) {
  627.        Bottom->SwitchFocus(M);
  628.     }
  629.      }
  630.      else {
  631.        switch(M.Code) {
  632.      case TabKey : 
  633.        NewIso = CycleForw(M.Focus);
  634.        if (NewIso != NULL) NewIso->SwitchFocus(M);
  635.      break;
  636.      case ShiftTabKey : 
  637.        // Cycle backwards ... not currently implemented 
  638.      break;
  639.          default: ;
  640.        }
  641.      }
  642.   }
  643. }
  644.  
  645. void IsoMgr::ResetTouchFlags(Iso *Me)
  646. {
  647.   while (Me != NULL) {
  648.      Me->TouchFlag = False;
  649.      Me = Me->Over;
  650.   }
  651. }
  652.  
  653. void IsoMgr::SetTouchFlags(Iso *Me)
  654. // Sets touch flags for all Iso's above Me that touch
  655. // Me. Must do this recursively for all touching Iso's.
  656. // Note that hidden Iso's are not included! 
  657. {
  658.   Iso *Ip;
  659.  
  660.   Ip = Me->Over;
  661.    while (Ip != NULL) {
  662.       if (Ip->Visible) { // Must be visible to be touching 
  663.      // The swappable check prevents flickering 
  664.      if ((Ip->Panel->IsSwappable()) &&
  665.         Me->Panel->Touches(Ip->Panel)) {
  666.         Me->TouchFlag = True;
  667.         Ip->TouchFlag = True;
  668.         SetTouchFlags(Ip); // Must do this!! 
  669.      }
  670.       }
  671.       Ip = Ip->Over;
  672.    }
  673. }
  674.  
  675. void IsoMgr::OnIso(int Mx, int My, Iso **I) 
  676. // Recursive routine that finds the highest Iso which contains
  677. // the coordinates Mx, and My. It looks through the sub-stack
  678. // first. If it can't find anyone there, it tries the
  679. // Base Iso. Note that hidden Iso's are not included! 
  680. {
  681.   Iso *P, *Q;
  682.   int Found;
  683.  
  684.   P = Top;  Found = False;
  685.   while ((P != NULL) && (!Found)) {
  686.     // Iso has to be visible to be elgible 
  687.     if (P->Visible && P->Panel->OnFrame(Mx, My)) {
  688.        Found = True;
  689.        P->SubMgr->OnIso(Mx, My, &Q);
  690.        if (Q != NULL) P = Q;
  691.     }
  692.     else {
  693.       P = P->Under;
  694.     }
  695.   }
  696.   if ((P == NULL) && (Base != NULL)) {
  697.      if (Base->Visible && Base->Panel->OnFrame(Mx, My))
  698.      P = Base;
  699.   }
  700.   *I = P;
  701. }
  702.  
  703. void IsoMgr::EventLoop(MsgPkt &M)
  704. // Loop through the event handler until either a Shutdown
  705. // event (Alt-X) occurs, or there are no Iso's on the stack 
  706. {
  707.   Iso *P;
  708.  
  709.   do {
  710.     EventStep(M);
  711.     M.Code = M.RtnCode;
  712.     P = Top;
  713.     while ((P != NULL) && (!P->Visible)) P = P->Under;
  714.   } while ((M.Code != ShutDown) && (P != NULL));
  715. }
  716.  
  717. void IsoMgr::EventStep(MsgPkt &M)
  718. // First, handle any p}ing events, look for new ones.
  719. // Also, monitor the mouse movement between Iso's. 
  720. {
  721.   Iso *HotIso;
  722.   unsigned E;
  723.  
  724.   // Handle any pending messages 
  725.   HotIso = NULL; // Very important to do this! 
  726.   if ((M.Code != Idle) && (M.Focus != NULL)) {
  727.      M.Focus->Dispatch(M); // Note: the focus might change here 
  728.   }
  729.   else { // Handle any key strokes 
  730.      E = KeyEvent();
  731.      if (E != Idle) {
  732.         M.Code = E;
  733.         ProcessCycle(M);  // Process possible cycle keys 
  734.      }
  735.      else { // Handle any mouse activity 
  736.         E = Mouse.Event(M.Mx, M.My);
  737.         OnIso(M.Mx, M.My, &HotIso);
  738.         if (HotIso != Hot) {
  739.            if (Hot != NULL) Hot->OnMouseLeave(M);
  740.            if (HotIso != NULL) HotIso->OnMouseEnter(M);
  741.         }
  742.         Hot = HotIso;
  743.      }
  744.      if (E != Idle) {
  745.        if (HotIso != M.Focus) {
  746.           if (M.Focus != NULL) M.Focus->OnMouseLeave(M);
  747.           if (HotIso != NULL)  HotIso->OnMouseEnter(M);
  748.        }
  749.      }
  750.      else if (M.Focus != NULL) E = MouseWithin;
  751.      M.RtnCode = E; // Key/mouse event becomes new message for Focus 
  752.   }
  753. }
  754.  
  755.